#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/devinfo.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/list.h>
#include <linux/printk.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/spinlock.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/ioctl.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/of_device.h>
#include <linux/acpi.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
#include <linux/usb.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/hid.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-event.h>
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-vmalloc.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <video/display_timing.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/fb.h>
#include <video/of_display_timing.h>
#include <video/of_videomode.h>
#include <video/videomode.h>
#include <linux/list.h>
#include <linux/input.h>
#include <linux/timer.h>


/* 参考gpio-keys.c */

// C语言零长数组
struct jz_input_dev_drvdata {
	struct input_dev *input;
	struct device *dev;
	unsigned int len;
	struct timer_list timer;
	char zero_buf[0];
};

static int jz_2440_input_dev_open(struct input_dev *input)
{
	struct jz_input_dev_drvdata *ddata = input_get_drvdata(input);
	dev_err(ddata->dev, "jz_2440_input_dev_open\n");

	// 添加定时器
	add_timer(&ddata->timer);
	// 设置第一次定时触发时间
	// ddata->timer.expires = jiffies + HZ * 10000;
	// 或者等待无限超时时间，等待其他触发
	ddata->timer.expires = jiffies + msecs_to_jiffies(-1);
	
	return 0;
}

static void jz_2440_input_dev_close(struct input_dev *input)
{
	struct jz_input_dev_drvdata *ddata = input_get_drvdata(input);
	dev_err(ddata->dev, "jz_2440_input_dev_close\n");

	// 删除定时器
	del_timer(&ddata->timer);
}

static void timer_function(struct timer_list *t)
{
	// 通过from_timer(container of)获取数据
	struct jz_input_dev_drvdata *ddata = NULL;
	ddata = from_timer(ddata, t, timer);
	if (!ddata) {
		dev_err(ddata->dev, "from_timer failed\n");
	}

	// 上报input type code value(1 按下/ 0 松开)
	input_event(ddata->input, EV_KEY, KEY_UP, 1);
	// 同步input事件
	input_sync(ddata->input);
	

	// 更新定时器时间 默认Linux是HZ设置的是100, HZ == 1 s     1 / 50 = 20 ms
	// mod_timer(&ddata->timer, jiffies + 5 * HZ);
	mod_timer(&ddata->timer, jiffies + msecs_to_jiffies(5000)); // 5s
	
}

static int jz_input_dev_probe(struct platform_device *pdev)
{
	struct device_node *np = NULL;
    struct device *dev = &pdev->dev;
    int ret = 0;
	struct input_dev *input;
	int zero_len = 16;
	struct jz_input_dev_drvdata *ddata = NULL;

	np = dev->of_node;
    if (!np) {
        dev_err(dev, "could not find device info\n");
        return -EINVAL;
    }

	// 分配零长数组+零长数组结构体大小
	ddata = devm_kzalloc(dev, sizeof(struct jz_input_dev_drvdata) + zero_len * sizeof(char), GFP_KERNEL);
	if (!ddata) {
		dev_err(dev, "failed to allocate state\n");
		return -ENOMEM;
	}

	// 分配设置input_dev
	input = devm_input_allocate_device(dev);
	if (!input) {
		dev_err(dev, "failed to allocate input device\n");
		return -ENOMEM;
	}

	ddata->input = input;
	ddata->dev = dev;

	// 保存平台数据
	platform_set_drvdata(pdev, ddata);
	input_set_drvdata(input, ddata);

	// 设置input信息
	input->name = pdev->name;
	input->phys = "jz2440-input-dev";
	input->dev.parent = dev;

	// 设置input的open/close函数
	input->open = jz_2440_input_dev_open;
	input->close = jz_2440_input_dev_close;

	// 设置input设备信息
	input->id.bustype = BUS_HOST;
	input->id.vendor = 0x0001;
	input->id.product = 0x0001;
	input->id.version = 0x0100;

	// 设置input支持的event type

	// 普通设置两种方法都可以
	// input_set_capability(input, EV_KEY, KEY_UP);

	// 直接设置input bit位
	__set_bit(EV_KEY, input->evbit);
	__set_bit(EV_REP, input->evbit); // 重复事件

	// 设置input支持的code
	__set_bit(KEY_UP, input->keybit);
	// __set_bit(KEY_DOWN, input->keybit);

	// 注册input_device
	ret = input_register_device(input);
	if (ret) {
		dev_err(dev, "Unable to register input device, error: %d\n",
			ret);
		return ret;
	}

	// 初始化定时器
	timer_setup(&ddata->timer, timer_function, 0);

	return 0;
}

static int jz_input_dev_remove(struct platform_device *pdev)
{	
	struct jz_input_dev_drvdata *ddata = platform_get_drvdata(pdev);
	input_unregister_device(ddata->input);	
		
	return 0;
}

static const struct of_device_id jz_input_dev[] = {
    { .compatible = "jz2440,input_dev", },
    {},
};
MODULE_DEVICE_TABLE(of, jz_input_dev);


static struct platform_driver input_dev_driver = {
    .probe = jz_input_dev_probe,
    .remove = jz_input_dev_remove,
    .driver = {
        .name = "jz2440-input-dev",
        .of_match_table = of_match_ptr(jz_input_dev),
    }
};


/*
 * init入口函数
*/
static int input_dev_init(void)
{
    int ret = platform_driver_register(&input_dev_driver);
    if (ret < 0) {
        dev_err(NULL, "input_dev_init failed\n");
        return -EBUSY;
    }
    
    return ret;
}

/*
 * exit出口函数
 */
static void input_dev_exit(void)
{
    platform_driver_unregister(&input_dev_driver);
    return;
}

module_init(input_dev_init);
module_exit(input_dev_exit);


MODULE_AUTHOR("huang");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("platform input dev");


